package  
{
  import mge.Timer;
	/**
   * ...
   * @author Ivan
   */
  public class AIController 
  {
    public static const MODE_EASY:String = "MODE_EASY";
    public static const MODE_HARD:String = "MODE_HARD";
    
    public function AIController(mode:String) 
    {
      this.mode = mode;
      
      if (mode == MODE_EASY) attackTimer.start();
    }
    
    public function command():UnitsTransfer
    {
      herTowns = GameBoard.towns.filter(enemyTownsFilter, this);
      myTowns = GameBoard.towns.filter(friendlyTownsFilter, this);
      neutralTowns = GameBoard.towns.filter(neutralTownsFilter, this);
      
      switch(mode)
      {
        case MODE_EASY: easyAICommand(); break;
        case MODE_HARD: hardAICommand(); break;
      }
      
      return null;
    }
    
    private function easyAICommand():void
    {        
      if (!attackTimer.finished())
        return;
        
      attackTimer.start();
      if (myTowns.length == 0) return;
      if (herTowns.length == 0) return;
      
      var source:Town = myTowns[(int)(Math.random() * myTowns.length)];
      
      var target:Town;
      
      if (neutralTowns.length > 0)
        target = neutralTowns[(int)(Math.random() * neutralTowns.length)]
      else
        target = herTowns[(int)(Math.random() * herTowns.length)];
      
      var transfer:UnitsTransfer = new UnitsTransfer();
      transfer.source = source;
      transfer.target = target;
      
      // return transfer;
      source.sendArmy(transfer);
    }
    
    private function hardAICommand():void
    {
      if (myTowns.length == 0) return;
      // Gives a score to each possible move (from each controlled town to each possible target).
      var moves:Vector.<EvaluatedMove> = new Vector.<EvaluatedMove>();
      for (var i:int = 0; i < myTowns.length; i++)
      for (var j:int = 0; j < GameBoard.towns.length; j++)
      {
        if (myTowns[i] == GameBoard.towns[j]) continue;
        var em:EvaluatedMove = new EvaluatedMove(myTowns[i], GameBoard.towns[j]);
        em.evaluate();
        moves.push(em);
      }
      
      var bestMove:EvaluatedMove = moves.sort(bigScoreFirst)[0];
      trace("best move: " + bestMove.score);
      if (bestMove.score >= 1)
      {
        var transfer:UnitsTransfer = new UnitsTransfer();
        transfer.source = bestMove.source;
        transfer.target = bestMove.target;
        transfer.source.sendArmy(transfer);
      }
    }
    
    private function neutralTownsFilter(t:Town, index:int, vector:Vector.<Town>):Boolean { return t.owner == null; }
    private function friendlyTownsFilter(t:Town, index:int, vector:Vector.<Town>):Boolean { return t.owner === player; }
    private function enemyTownsFilter(t:Town, index:int, vector:Vector.<Town>):Boolean { return t.owner && t.owner != player; }
    private function bigTownFirst(a:Town, b:Town):Number
    { 
      if (a.populationLimit == b.populationLimit) return 0;
      return a.populationLimit < b.populationLimit ? +1 : -1;
    }
    private function bigScoreFirst(a:EvaluatedMove, b:EvaluatedMove):Number
    {
      if (a.score < b.score) return +1;
      if (a.score > b.score) return -1;
      return 0;
    }
    
    public var player:Player;
    
    private var herTowns:Vector.<Town>;
    private var myTowns:Vector.<Town>;
    private var neutralTowns:Vector.<Town>;
    private var mode:String;
    private var attackTimer:Timer = new mge.Timer(5000);
    
  }

}

import flash.geom.Point;

internal class EvaluatedMove
{
  public function EvaluatedMove(source:Town, target:Town)
  {
    this.source = source;
    this.target = target;
  }
  
  public function evaluate():void
  {
    /**
     * Base score.
     */
    
    if (source.owner != target.owner)
    {
      // Overnumber conditions are good
      if (source.population > target.population * 2) score += 0.6;
      else if (source.population > target.population * 1.5) score += 0.3;
      else if (source.population > target.population * 1.2) score += 0.15;
      
      // Empty bases are really good
      if (target.population == 0) score += 0.5;
      
      // Big bases are betters than small ones.
      if (target.populationLimit > 40) score += 0.3;
      else if (target.populationLimit > 30) score += 0.2;
      else if (target.populationLimit > 15) score += 0.1;
      
      // Leave town undefended is not good idea
      if (source.population < source.populationLimit * 0.2) score -= 0.8;
      else if (source.population < source.populationLimit * 0.4) score -= 0.5;
      else if (source.population < source.populationLimit * 0.6) score -= 0.3;
      else if (source.population < source.populationLimit * 0.8) score -= 0.1;
      
    }
    
    // Reinforce cities could be good.
    if (target.owner == source.owner)
    {
      if (source.population == source.populationLimit) 
        score += 0.3;
    }
    
    /**
     *  Overall modifiers.
     */
    
    // Moving this army is good idea to not interrupt units production.
    if (source.population == source.populationLimit)
    {
      score *= 1.5;
    }
    
    // Near is good
    var distance:Number = new Point(source.x, source.y).subtract(new Point(target.x, target.y)).length;
    if (distance <= 100) score *= 1.2;
    else if (distance <= 200) score *= 1.15;
    else if (distance <= 300) score *= 1.1;
    else if (distance <= 400) score *= 1.06;
    
  }
  
  public var source:Town;
  public var target:Town;
  public var score:Number = 0;
}